package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.CommonCodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.Product;
import cn.wolfcode.domain.SeckillProduct;
import cn.wolfcode.domain.SeckillProductVo;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.web.feign.ProductFeignApi;
import com.alibaba.fastjson.JSON;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.aspectj.weaver.ast.Var;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service
public class SeckillProductServiceImpl implements ISeckillProductService {
    @Autowired(required = false)
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Resource
    private ProductFeignApi productFeignApi;

    /**
     * 1  查询秒杀商品集合
     * 2   分离出来 产品id集合
     * 3  feign调用调用商品服务， 传递商品id集合，返回商品集合
     * 4  产品集合转换为产品map
     * 5  遍历秒杀商品及和和map，  获取voList
     * 6  返回这个voList
     *
     * @return
     */
    @Override
    public List<SeckillProductVo> queryAllCurrent() {
        //1  查询秒杀商品集合
        List<SeckillProduct> seckillProductList = seckillProductMapper.queryAllProducts();
        return getSeckillProductVos(seckillProductList);
    }

    private List<SeckillProductVo> getSeckillProductVos(List<SeckillProduct> seckillProductList) {
        if (StringUtils.isEmpty(seckillProductList) || seckillProductList.size() == 0) {
            return Collections.emptyList();
        }


        //2   分离出来 产品id集合
//        List<Long> productIds = new ArrayList();
//        for (SeckillProduct seckillProduct : seckillProductList) {
//            productIds.add(seckillProduct.getProductId());
//        }
        List<Long> productIds = seckillProductList.stream().map(SeckillProduct::getProductId).collect(Collectors.toList());

        //3  feign调用调用商品服务， 传递商品id集合，返回商品集合
        Result<List<Product>> result = productFeignApi.findByIds(productIds);

        // 为null 降级
        if (StringUtils.isEmpty(result) || result.hasError()) {
            throw new BusinessException(CommonCodeMsg.RESULT_IS_EMPTY);
        }
        if (StringUtils.isEmpty(result.getData()) || result.getData().size() == 0) {
            return Collections.emptyList();
        }

        //4  产品集合转换为产品map
        Map<Long, Product> productMap = result.getData().stream().collect(Collectors.toMap(Product::getId, p -> p));

//        Map<Long, Product> map = new HashMap<>();
//        for (Product product : result.getData()) {
//            map.put(product.getId(), product);
//        }

        //5  遍历秒杀商品及和和map，  获取voList
        List<SeckillProductVo> ret = seckillProductList.stream().map(
                seckillProduct -> {
                    SeckillProductVo seckillProductVo = new SeckillProductVo();
                    Product product = productMap.get((seckillProduct.getProductId()));
                    BeanUtils.copyProperties(product, seckillProductVo);
                    BeanUtils.copyProperties(seckillProduct, seckillProductVo);
                    return seckillProductVo;
                }
        ).collect(Collectors.toList());
//
//        List<SeckillProductVo> ret = new ArrayList<>();
//        for (SeckillProduct seckillProduct : seckillProductList) {
//            SeckillProductVo vo = new SeckillProductVo();
//            BeanUtils.copyProperties(seckillProduct, vo);
//            Product product = map.get(seckillProduct.getProductId());
//            BeanUtils.copyProperties(product, vo);
//            ret.add(vo);
//        }

        return ret;
    }

    /**
     * 1  从redis中获取
     * 2  从mysql中获取
     * 1）查询秒杀商品列表信息
     * 2）分离出来产品id集合
     * 3）feign调用获取产品集合
     * 4）产品集合变为产品map
     * 5）合成voList
     * 3  把数据放到redis中
     *
     * @param time
     * @return
     */
    @Override
    public List<SeckillProductVo> queryByTime(Integer time) {
        String seckillBigKey = SeckillRedisKey.SECKILL_PRODUCT_HASH.getRealKey(time.toString());
        //获取大key里的所有value
        List<Object> values = redisTemplate.opsForHash().values(seckillBigKey);
        if (!StringUtils.isEmpty(values) && values.size() > 0) {
            return values.stream()
                    .map(v -> JSON.parseObject(v.toString(), SeckillProductVo.class))
                    .collect(Collectors.toList());
        }

        List<SeckillProduct> seckillProductList = seckillProductMapper.queryCurrentlySeckillProduct(time);
        //2  传递进来seckillProductList
        List<SeckillProductVo> voList = getSeckillProductVos(seckillProductList);

        if (StringUtils.isEmpty(voList) || voList.size() == 0) {
            return Collections.emptyList();
        }

        voList.stream().collect(Collectors.groupingBy(vo -> vo.getTime())).forEach((k, v) -> {
            //处理vo
            String seckill2BigKey = SeckillRedisKey.SECKILL_PRODUCT_HASH.getRealKey(k.toString());
            Map<String, String> voMap = v.stream().collect(Collectors.toMap(v2 -> String.valueOf(v2.getId()), v2 -> JSON.toJSONString(v2)));
            redisTemplate.opsForHash().putAll(seckill2BigKey, voMap);

            //库存
            String storeBigKey = SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(k.toString());
            Map<String, String> storeMap =
                    v.stream().collect(
                            Collectors.toMap(
                                    v2 -> String.valueOf(v2.getId()), v2 -> v2.getStockCount().toString()));
            redisTemplate.opsForHash().putAll(storeBigKey, storeMap);
        });

        return voList;

 /*
        //类型转换  Object  --> String
        List<String> seckillProductList = values.stream().map(e -> String.valueOf(e)).collect(Collectors.toList());
        //类型转换  Json -->  SeckillProductVo
        List<SeckillProductVo> vos = seckillProductList.stream().map(e -> JSON.parseObject(e, SeckillProductVo.class)).collect(Collectors.toList());
//        List<SeckillProductVo> vos = new ArrayList<>();
//        for (String value : seckillProductList) {
//            vos.add(JSON.parseObject(value, SeckillProductVo.class));
//        }
        return vos;

  */
    }

    @Override
    public SeckillProductVo find(Integer time, Long seckillId) {
        //1 从redis中取
        String seckillBigKey = SeckillRedisKey.SECKILL_PRODUCT_HASH.getRealKey(time.toString());
        //获取大key里的所有value
        String json = (String) redisTemplate.opsForHash().get(seckillBigKey, String.valueOf(seckillId));
        if (!StringUtils.isEmpty(json)) {
            return JSON.parseObject(json, SeckillProductVo.class);
        }

        //2 从mysql中取
        //1 查询秒杀商品
        SeckillProduct seckillProduct = seckillProductMapper.get(seckillId);
        List<SeckillProduct> seckillProductList = Arrays.asList(seckillProduct);
        //2 调用上面的逻辑，  传递进来seckillProduct , 返回vo
        List<SeckillProductVo> voList = getSeckillProductVos(seckillProductList);
        SeckillProductVo seckillProductVo = voList.get(0);
        //3 把数据放到redis中
        redisTemplate.opsForHash().put(seckillBigKey, String.valueOf(seckillId), JSON.toJSONString(seckillProductVo));

        //库存
        String storeBigKey = SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(time.toString());
        redisTemplate.opsForHash()
                .put(storeBigKey, String.valueOf(seckillId), seckillProductVo.getStockCount().toString());
        return seckillProductVo;
    }

    @Override
    public SeckillProductVo queryVoFromDB(Long seckillId) {
        SeckillProduct seckillProduct = seckillProductMapper.get(seckillId);
        List<SeckillProduct> seckillProductList = Arrays.asList(seckillProduct);
        //2 调用上面的逻辑，  传递进来seckillProduct , 返回vo
        List<SeckillProductVo> voList = getSeckillProductVos(seckillProductList);
        SeckillProductVo seckillProductVo = voList.get(0);
        return seckillProductVo;
    }

    @Override
    public int decrStock(Long seckillId) {
        return  seckillProductMapper.decrStock(seckillId);
    }

    @Override
    public SeckillProduct queryFomDB(Long seckillId) {
        SeckillProduct seckillProduct = seckillProductMapper.get(seckillId);
        return seckillProduct;
    }

    @Override
    public int inscrStore(Long seckillId) {
        return seckillProductMapper.incrStock(seckillId);
    }
}
